﻿using System;
using System.Drawing;
using GeoSketch2.Core;
using System.Xml;
using System.IO;

namespace GeoSketch2.Archaeo
{
    /// <summary>
    /// A 2D point for geosketch
    /// </summary>
    public class Point2D:BaseArchaeoDrawableObject
    {
        #region XMLElementsName
#pragma warning disable 1591
        public const string XML_Position = "Position";
#pragma warning restore 1591
        #endregion

        #region Fields
        /// <summary>
        /// The location of the point
        /// </summary>
        public Point2D64D Position; 
        #endregion

        #region Constructor
        /// <summary>
        /// A point with 2D coordinates
        /// </summary>
        /// <param name="Point">The location of the point</param>
        /// <param name="Layer">The layer of the point</param>
        /// <param name="ExcavationUnit">The excavation unit of the object</param>
        public Point2D(Point2D64D Point, Layer Layer, ExcavationArea ExcavationArea)
            : this(Point, Layer, ExcavationArea, ColorByLayer())
        {
        }

        /// <summary>
        /// A point with 2D coordinates
        /// </summary>
        /// <param name="Point">The location of the point</param>
        /// <param name="Layer">The layer of the point</param>
        /// <param name="ExcavationUnit">The excavation unit of the object</param>
        /// <param name="Color">The color of the point</param>
        public Point2D(Point2D64D Point, Layer Layer, ExcavationArea ExcavationArea, Color Color)
            : this(Point, Layer, ExcavationArea, Color, LineTypeByLayer())
        {            
        }

        /// <summary>
        /// A point with 2D coordinates
        /// </summary>
        /// <param name="Point">The location of the point</param>
        /// <param name="Layer">The layer of the point</param>
        /// <param name="Color">The color of the point</param>
        /// <param name="ExcavationUnit">The excavation unit of the object</param>
        /// <param name="LineType">The type of line of the point</param>
        public Point2D(Point2D64D Point, Layer Layer, ExcavationArea ExcavationArea, Color Color, LineType LineType)
            : this(Point, Layer, ExcavationArea, Color, LineType, "")
        {
        }

        /// <summary>
        /// A point with 2D coordinates
        /// </summary>
        /// <param name="Point">The location of the point</param>
        /// <param name="Layer">The layer of the point</param>
        /// <param name="Color">The color of the point</param>
        /// <param name="ExcavationUnit">The excavation unit of the object</param>
        /// <param name="Comment">The comment about of the point</param>
        /// <param name="LineType">The type of line of the point</param>
        public Point2D(Point2D64D Point, Layer Layer, ExcavationArea ExcavationArea, Color Color, LineType LineType, string Comment)
            : this(Point, Layer, ExcavationArea, Color, LineType, Comment, DateTime.Now)
        {
        }

        /// <summary>
        /// A point with 2D coordinates
        /// </summary>
        /// <param name="Point">The location of the point</param>
        /// <param name="Layer">The layer of the point</param>
        /// <param name="Color">The color of the point</param>
        /// <param name="ExcavationUnit">The excavation unit of the object</param>
        /// <param name="Comment">The comment about of the point</param>
        /// <param name="CreationTime">The date of creation of the object</param>
        /// <param name="LineType">The type of line of the point</param>
        public Point2D(Point2D64D Point, Layer Layer, ExcavationArea ExcavationArea, Color Color, LineType LineType, string Comment, DateTime CreationTime)
            : base(Layer, Color, LineType, ExcavationArea, Comment, CreationTime)
        {
            this.Position = Point;
        }

        /// <summary>
        /// A point with 2D coordinates
        /// </summary>
        /// <param name="Xr">The xml reader to read from</param>
        /// <param name="Site">The excvation site</param>
        public Point2D(XmlReader Xr, ArchaeoProject Project)
            : base(Xr, Project)
        {
            Xr.ReadToFollowing(XML_SpecificInfos);

            #region Position
            Xr.ReadToFollowing(XML_Position);
            Xr.ReadToFollowing(typeof(Point2D64D).FullName);
            this.Position = new Point2D64D(Xr);
            Xr.ReadEndElement();
            #endregion

            Xr.ReadEndElement();

            Xr.ReadEndElement();
        }
        #endregion

        #region Methods
        /// <summary>
        /// Draws the point if unselected
        /// </summary>
        /// <param name="Viewport">The viewport to draw to</param>
        protected override void DrawUnselected(BaseViewport Viewport)
        {
            DrawCustomPen(Viewport, Pen);
        }

        /// <summary>
        /// Draws the point if unselected
        /// </summary>
        /// <param name="Viewport">The viewport to draw to</param>
        protected override void DrawSelected(BaseViewport Viewport)
        {
            DrawCustomPen(Viewport, Core.Vars.Setup.Tools.TSelection.SelectionPen);
        }

        /// <summary>
        /// Draws the point if unselected
        /// </summary>
        /// <param name="Viewport">The viewport to draw to</param>
        /// <param name="CustomPen">The pen to draw with</param>
        public override void DrawCustomPen(BaseViewport Viewport, Pen CustomPen)
        {
            Point2D64D Point_screen = Viewport.Object2ImageTransformation.Transform(Position);
            Viewport.Graphic.DrawLine(CustomPen, Point_screen, Point_screen + new Point2D64D(-Vars.Setup.DrawableObjects.Point2D.CrossRadius, -Vars.Setup.DrawableObjects.Point2D.CrossRadius));
            Viewport.Graphic.DrawLine(CustomPen, Point_screen, Point_screen + new Point2D64D(Vars.Setup.DrawableObjects.Point2D.CrossRadius, -Vars.Setup.DrawableObjects.Point2D.CrossRadius));
            Viewport.Graphic.DrawLine(CustomPen, Point_screen, Point_screen + new Point2D64D(-Vars.Setup.DrawableObjects.Point2D.CrossRadius, Vars.Setup.DrawableObjects.Point2D.CrossRadius));
            Viewport.Graphic.DrawLine(CustomPen, Point_screen, Point_screen + new Point2D64D(Vars.Setup.DrawableObjects.Point2D.CrossRadius, Vars.Setup.DrawableObjects.Point2D.CrossRadius));
           
            if (Vars.Setup.DrawableObjects.Point2D.DrawId)
            {
                Viewport.Graphic.DrawString(Id.ToString(),
                    Vars.Setup.DrawableObjects.Point2D.IdFont,
                    CustomPen.Brush,
                    Viewport.Object2ImageTransformation.Transform(Position) + new Point2D64D(Vars.Setup.DrawableObjects.Point2D.CrossRadius + 1, Vars.Setup.DrawableObjects.Point2D.CrossRadius + 1));
            }
        }

        /// <summary>
        /// The method to test if the GeoPoint is near to the point clicked, for an object selection purpose
        /// </summary>
        /// <param name="Clic">The point clicked in object coordinates</param>
        /// <param name="IsNearDistance">The distance under which the clic is near to the object</param>
        public override bool IsNear(Point2D64D Clic, double IsNearDistance)
        {
            double distance = Position.Distance2D(Clic);

            if (distance < IsNearDistance)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// Gets the nearest point to the click
        /// </summary>
        /// <param name="Clic">The point clicked in object coordinates</param>
        /// <param name="IsNearDistance">The distance under which the clic is near to the object</param>
        public override Point2D64D NearestPoint(Point2D64D Clic, double IsNearDistance)
        {
            if (IsNear(Clic, IsNearDistance))
            {
                return Position;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Gets a clone of the object
        /// </summary>
        public override T Clone<T>()
        {
            return (T)(object)new Point2D(Position.DeepClone(), Layer, ExcavationArea, this._ObjectColor,this._LineType, Comment);
        }

        /// <summary>
        /// Translates the object
        /// </summary>
        public override void Translate(Point2D64D Vector)
        {
            Position.X += Vector.X;
            Position.Y += Vector.Y;
        }

        /// <summary>
        /// Writes the object to an xml file
        /// </summary>
        /// <param name="Xw">The XmlWriter to write to</param>
        public override void ToFile(XmlWriter Xw)
        {
            Xw.WriteStartElement(this.GetType().FullName);

            #region Object Base Information
            this.BaseInfosToFile(Xw);
            #endregion

            #region Object Specific Information
            Xw.WriteStartElement(XML_SpecificInfos);

            #region Position
            Xw.WriteStartElement(XML_Position);
            this.Position.ToFile(Xw);
            Xw.WriteEndElement();
            #endregion

            Xw.WriteEndElement();
            #endregion

            Xw.WriteEndElement();
        }

        public override void ToDXFr13(TextWriter Tw)
        {
            Tw.WriteLine("0");
            Tw.WriteLine("POINT");

            this.BaseInfosToDXFR13(Tw);

            Tw.WriteLine("10");
            Tw.WriteLine(this.Position.X.ToString(Core.Vars.Setup.GeoSketch.NumberFormat));

            Tw.WriteLine("20");
            Tw.WriteLine(this.Position.Y.ToString(Core.Vars.Setup.GeoSketch.NumberFormat));

            Tw.WriteLine("30");
            Tw.WriteLine("0.0");
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets the bounds of the object
        /// </summary>
        public override RectangleD Bounds
        {
            get
            {
                return RectangleD.FromCenter(Position, 1, 1, YAxisDirection.UpSide);
            }
        } 
        #endregion
    }
}
